﻿/*
 * created by tophy V1.0
 * Interface of for to dynamic page script by XML data structure
 * for xml document format , see XMLDataInterfaceDocuments.txt
 * 2008-2-10 22:06
*/

import mx.utils.Delegate;
dynamic class XMLDataInterface{
	public static var ShowLoadStr:Boolean=false;
	public static var ShowSendStr:Boolean=true;
	public static var SAY:Boolean=true;
	public static var M_RESULT:String="result";
	public static var M_PROGRESS:String="progress";
	
	
	private static var lb_actions_b:String="<actions>";
	private static var lb_actions_e:String="</actions>";
	private static var lb_action_b:String="<action>";
	private static var lb_action_e:String="</action>";
	private static var lb_name_b:String="<name>";
	private static var lb_name_e:String="</name>";
	private static var lb_args_b:String="<args>";
	private static var lb_args_e:String="</args>";
	private static var lb_cdata_b:String="<![CDATA[";
	private static var lb_cdata_e:String="]]>";
	//////////////////////////////////////////////////////////////////////////
	
	private var __invId:Number;
	
	private var $url:String;
	private var $say:Say;
	private var $xml:XML;
	private var $xmlrs:XML;
	
	private var $Actioning:Boolean;
	private var $asValue:Boolean=false;
	
	//////////////////////////////////////////////////////////////////////////
	public function get AsValue():Boolean{
		return this.$asValue;
	}
	public function set AsValue(value:Boolean){
		this.$asValue=value;
	}
	
	public function get say():Say{
		return this.$say;
		
	}
	public function get Url():String{
		return this.$url;
	}
	public function set Url(value:String){
		this.$url=value;
	}
	public function get lastSendXml():String{
		return this.$xml.toString();
	}
	public function get lastLoadXml():String{
		return this.$xmlrs.toString();
	}
	//////////////////////////////////////////////////////////////////////////
	public function XMLDataInterface(url:String){
		this.$url=url;
		this.initBroadcase();
		initvars();
		this.$say.msay("interface["+url+"] initok!");
	}
	
	public function Action():Boolean{
		if(this.$url==undefined || this.$url==""){
			this.onErrorFun("Post Url is undefined!");
			return false;
		}
		if(this.$Actioning){
			this.onErrorFun("The Action["+arguments+"] can't been excute when other Action is working.");
			return false;
		}else{
			this.initxml();
			
			if(arguments.length>1){
				this.praseActionXml(arguments[0],arguments[1]);
			}else if(arguments.length==1){
				this.praseActionXmls(arguments[0]);
			}else{
				this.onErrorFun("Action with error parameters.["+arguments+"]");
				return false;
			}
			/**/
			this.$say.msay("ACTION:"+arguments[0]);
			if(ShowSendStr){
				this.$say.msay("sendstring:\r"+this.lastSendXml);
			}
			//..........................
			var sendstr:String="";
			if(this.$asValue){
				sendstr="&xmlstring="+this.lastSendXml;
			}
			if(this.$url.substring(this.$url.length-3).toLowerCase()!="xml"){
				this.$xml.sendAndLoad(this.$url+"?___="+int(Math.random()*1000).toString()+sendstr,this.$xmlrs);
			}else{
				this.$xml.sendAndLoad(this.$url,this.$xmlrs);
			}
			if(this.__invId>=0){
				clearInterval(this.__invId);
			}
			this.__invId=setInterval(this.startProgress,200,this);
			return true;
		}
	}
	private function startProgress(tag:XMLDataInterface){
		//trace(tag+"||||||");
		var ll:Number=tag.$xmlrs.getBytesLoaded();
		var tt:Number=tag.$xmlrs.getBytesTotal();
		tag.broadcastMessage(M_PROGRESS,tag,ll,tt);
	}
	private function praseActionXml(mothedId:String,args:Object){
		return praseActionXmls([{mothedId:mothedId,args:args}]);
	}
	private function praseActionXmls(tasks:Array){
		if(tasks.length<=0){
			return "";
		}
		
		var xmlstr:String=XMLDataInterface.lb_actions_b;
		for(var i=0;i<tasks.length;i++){
			var task:Object=tasks[i];
			xmlstr+=lb_action_b;
			xmlstr+=lb_name_b;
			xmlstr+=task.mothedId;
			xmlstr+=lb_name_e;
			xmlstr+=lb_args_b;
			for(var n in task.args){
				xmlstr+="<"+n+">";
				xmlstr+=lb_cdata_b+task.args[n].toString()+lb_cdata_e;
				xmlstr+="</"+n+">"
			}
			xmlstr+=lb_args_e;
			xmlstr+=lb_action_e;
		}
		this.$xml.parseXML(xmlstr);
		return xmlstr;
	}
	private function initxml(){
		if(this.$xml!=undefined){
			this.$xmlrs.onData=null;
			this.$xmlrs.onLoad=null;
		}
		this.$xml=new XML();
		this.$xmlrs=new XML();
		this.$xmlrs.ignoreWhite=true;
		this.$xmlrs.onLoad=Delegate.create(this,this.XmlOnLoad);
		this.$xmlrs.onData=Delegate.create(this,this.XmlOnData);
	}
	private function XmlOnData(xmlStr:String){		
		if(xmlStr==undefined || xmlStr==""){
			this.$xmlrs.onLoad(false);
			this.stopLoadingProgress();
		}else{
			this.$xmlrs.parseXML(xmlStr);
			this.$xmlrs.loaded=true;
			this.$xmlrs.onLoad(true);
		}
	}
	private function stopLoadingProgress(){
		clearInterval(this.__invId);
	}
	private function XmlOnLoad(success:Boolean){
		if(success){
			this.say.msay("XML loaded.");
			this.onXmlLoaded();
		}else{
			this.onErrorFun("send or load xml Error.");
		}
		this.$Actioning=false
	}
	private function onXmlLoaded(){
		this.$xmlrs.ignoreWhite=true;
		var xmn:XMLNode=this.$xmlrs.firstChild;
		var xmn1:XMLNode=this.$xmlrs.childNodes[1];
		if(this.$xmlrs.childNodes.length==1 && xmn.toString().length>3){
			this.praseXmlToObject(xmn);
			this.stopLoadingProgress();
		}else if(this.$xmlrs.childNodes.length==2 && xmn1.toString().length>3){
			this.praseXmlToObject(xmn1);
			this.stopLoadingProgress();
		}else{
			this.stopLoadingProgress();
			this.onErrorFun("send or load xml Error.xml document:\r["+this.$xmlrs.toString()+"]");
		}
	}
	private function praseXmlToObject(xmn:XMLNode){
		this.$say.msay("start prase xml data...");
		/*for test*/
		//Alert.show(xmn.toString(),"debug",Alert.OK,_root,null,"",Alert.OK);
		/*for test*/
		var rsNodes:Array=xmn.childNodes;
		var rtObj:Object=new Object();
		for(var i=0;i<rsNodes.length;i++){
			var nd:XMLNode=rsNodes[i];
			var type:String=nd.attributes["type"].toString();
			var name:String=nd.attributes["name"].toString();
			if(name==undefined){
				this.$say.wsay("error node["+nd.toString()+"]");
				continue;
			}
			if(rtObj[name]!=undefined){
				this.$say.wsay("node["+name+"] is exist.");
				continue;
			}
			if(type.toLowerCase()=="table"){
				rtObj[name]=new Array();
				var subnd:Array=nd.childNodes;
				for(var ii=0;ii<subnd.length;ii++){
					var tempnd:XMLNode=subnd[ii];
					var items:Array=tempnd.childNodes;
					var itemobj:Object=new Object();
					for(var itid=0;itid<items.length;itid++){
						var item:XMLNode=items[itid];
						var itemname:String=item.attributes["name"].toString();
						var itemvalue:String=item.attributes["value"].toString();
						if(itemobj[itemname]!=undefined){
							this.$say.wsay("item["+name+"] is exist.");
							continue;
						}else{
							itemobj[itemname]=itemvalue;
						}
					}
					rtObj[name].push(itemobj);
				}
			}else if(type.toLowerCase()=="array"){
				rtObj[name]=new Array();
				var subnd:Array=nd.childNodes;
				for(var ii=0;ii<subnd.length;ii++){
					var item:XMLNode=subnd[ii];
					rtObj[name].push(item.attributes["value"].toString());
				}
			}else if (type.toLowerCase()=="value"){
				rtObj[name]=nd.attributes["value"].toString();
			}else if(type.toLowerCase()=="xml"){
				var tempxmlstr:String="";
				for(var l=0;l<nd.childNodes.length;l++){
					tempxmlstr+=nd.childNodes[l].toString();
				}
				rtObj[name]=new XML(tempxmlstr);
			}
			else{
				this.$say.wsay("error type["+type+"]");
			}
		}
		this.onResult(rtObj,"parse ok!");
		return rtObj;
	}
	private function onResult(obj:Object,msg:String){
		if(!ShowLoadStr){
			this.say.msay(msg);
		}else{
			this.say.msay(msg+"result:\r"+this.lastLoadXml);
		}
		////////////////////////////////////////////////////////
		this.broadcastMessage(XMLDataInterface.M_RESULT,true,obj,msg);
	}
	
	/*
	 * onerror
	 */
	private function onErrorFun(msg:String){
		this.$say.esay("!!"+msg);
		this.broadcastMessage(XMLDataInterface.M_RESULT,false,null,msg);
	}
	//////////////////////////////////////////////////////////////////////////
	private function initvars(){
		this.$say=new Say("DI"+(new Date()).getTime().toString().substring(6));
		this.$Actioning=false;
		this[Say.M_SAY]=this.sayfun;
		this.$say.addListener(this);
		this.__invId=-1;
	}
	private function sayfun(o:Object){
		if(SAY){
			trace(o);
		}
	}
	private function initBroadcase(){
		AsBroadcaster.initialize(this);
		this.addListener(this);
	}
	
}